//! 日志级别定义模块
//!
//! 定义 log4r 支持的 6 个日志级别及其相关操作。
//!
//! ## 主要类型
//!
//! - [`Level`] - 日志级别枚举（TRACE, DEBUG, INFO, WARN, ERROR, FATAL）
//! - [`ParseLevelError`] - 级别解析错误
//!
//! ## 示例
//!
//! ```rust
//! use log4r::Level;
//! use std::str::FromStr;
//!
//! // 级别比较
//! assert!(Level::Trace < Level::Debug);
//! assert!(Level::Error < Level::Fatal);
//!
//! // 从字符串解析（大小写不敏感）
//! assert_eq!(Level::from_str("info").unwrap(), Level::Info);
//! assert_eq!(Level::from_str("INFO").unwrap(), Level::Info);
//! ```

use std::fmt;
use std::str::FromStr;

use serde::Deserialize;

/// 日志级别枚举
///
/// log4r 支持 6 个日志级别，从低到高排序：
/// - `Trace` - 最详细的跟踪信息
/// - `Debug` - 调试信息
/// - `Info` - 一般信息
/// - `Warn` - 警告信息
/// - `Error` - 错误信息
/// - `Fatal` - 致命错误，自动写入系统日志
///
/// ## 与 tracing 的映射
///
/// | log4r | tracing |
/// |-------|---------|
/// | Trace | TRACE |
/// | Debug | DEBUG |
/// | Info | INFO |
/// | Warn | WARN |
/// | Error | ERROR |
/// | Fatal | ERROR + fatal=true 标记 |
///
/// ## 反序列化
///
/// 支持大小写不敏感的字符串反序列化：
///
/// ```rust
/// use log4r::Level;
///
/// // 使用 toml 反序列化
/// let level: Level = toml::from_str("level = \"info\"")
///     .map(|v: toml::Value| v["level"].as_str().unwrap().parse().unwrap())
///     .unwrap();
/// assert_eq!(level, Level::Info);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum Level {
    /// 最详细的跟踪信息
    Trace = 0,
    /// 调试信息
    Debug = 1,
    /// 一般信息
    Info = 2,
    /// 警告信息
    Warn = 3,
    /// 错误信息
    Error = 4,
    /// 致命错误，自动写入系统日志
    Fatal = 5,
}

impl Level {
    /// 返回级别的大写字符串表示
    ///
    /// # 示例
    ///
    /// ```rust
    /// use log4r::Level;
    ///
    /// assert_eq!(Level::Info.as_str(), "INFO");
    /// assert_eq!(Level::Fatal.as_str(), "FATAL");
    /// ```
    #[inline]
    pub const fn as_str(&self) -> &'static str {
        match self {
            Level::Trace => "TRACE",
            Level::Debug => "DEBUG",
            Level::Info => "INFO",
            Level::Warn => "WARN",
            Level::Error => "ERROR",
            Level::Fatal => "FATAL",
        }
    }

    /// 转换为 tracing::Level
    ///
    /// FATAL 级别是 log4r 独有的，tracing 没有对应级别，
    /// 因此 FATAL 返回 `None`。
    ///
    /// # 示例
    ///
    /// ```rust
    /// use log4r::Level;
    ///
    /// assert_eq!(Level::Info.to_tracing_level(), Some(tracing::Level::INFO));
    /// assert_eq!(Level::Fatal.to_tracing_level(), None);
    /// ```
    #[inline]
    pub const fn to_tracing_level(&self) -> Option<tracing::Level> {
        match self {
            Level::Trace => Some(tracing::Level::TRACE),
            Level::Debug => Some(tracing::Level::DEBUG),
            Level::Info => Some(tracing::Level::INFO),
            Level::Warn => Some(tracing::Level::WARN),
            Level::Error => Some(tracing::Level::ERROR),
            Level::Fatal => None, // log4r 独有级别
        }
    }

    /// 检查当前级别是否应该被记录
    ///
    /// 如果当前级别 >= 过滤级别，则应该记录。
    ///
    /// # 示例
    ///
    /// ```rust
    /// use log4r::Level;
    ///
    /// let filter = Level::Info;
    /// assert!(!Level::Debug.should_log(filter)); // Debug < Info，不记录
    /// assert!(Level::Info.should_log(filter));   // Info >= Info，记录
    /// assert!(Level::Error.should_log(filter));  // Error > Info，记录
    /// ```
    #[inline]
    pub const fn should_log(&self, filter: Level) -> bool {
        (*self as u8) >= (filter as u8)
    }
}

impl fmt::Display for Level {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.as_str())
    }
}

/// Level 解析错误
///
/// 当尝试从无效字符串解析 Level 时返回此错误。
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseLevelError {
    /// 无效的输入字符串
    pub invalid_input: String,
}

impl fmt::Display for ParseLevelError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "无效的日志级别: '{}'", self.invalid_input)
    }
}

impl std::error::Error for ParseLevelError {}

// 自定义 Deserialize 实现，支持大小写不敏感
impl<'de> Deserialize<'de> for Level {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        Level::from_str(&s).map_err(|e| serde::de::Error::custom(e.to_string()))
    }
}

impl FromStr for Level {
    type Err = ParseLevelError;

    /// 从字符串解析日志级别（大小写不敏感）
    ///
    /// # 示例
    ///
    /// ```rust
    /// use log4r::Level;
    /// use std::str::FromStr;
    ///
    /// assert_eq!(Level::from_str("trace").unwrap(), Level::Trace);
    /// assert_eq!(Level::from_str("TRACE").unwrap(), Level::Trace);
    /// assert_eq!(Level::from_str("Trace").unwrap(), Level::Trace);
    ///
    /// assert!(Level::from_str("invalid").is_err());
    /// ```
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s.to_uppercase().as_str() {
            "TRACE" => Ok(Level::Trace),
            "DEBUG" => Ok(Level::Debug),
            "INFO" => Ok(Level::Info),
            "WARN" => Ok(Level::Warn),
            "ERROR" => Ok(Level::Error),
            "FATAL" => Ok(Level::Fatal),
            _ => Err(ParseLevelError {
                invalid_input: s.to_string(),
            }),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_level_ordering() {
        assert!(Level::Trace < Level::Debug);
        assert!(Level::Debug < Level::Info);
        assert!(Level::Info < Level::Warn);
        assert!(Level::Warn < Level::Error);
        assert!(Level::Error < Level::Fatal);
    }

    #[test]
    fn test_level_display() {
        assert_eq!(Level::Trace.to_string(), "TRACE");
        assert_eq!(Level::Debug.to_string(), "DEBUG");
        assert_eq!(Level::Info.to_string(), "INFO");
        assert_eq!(Level::Warn.to_string(), "WARN");
        assert_eq!(Level::Error.to_string(), "ERROR");
        assert_eq!(Level::Fatal.to_string(), "FATAL");
    }

    #[test]
    fn test_level_from_str() {
        assert_eq!(Level::from_str("trace"), Ok(Level::Trace));
        assert_eq!(Level::from_str("TRACE"), Ok(Level::Trace));
        assert_eq!(Level::from_str("Trace"), Ok(Level::Trace));
    }

    #[test]
    fn test_level_from_str_invalid() {
        assert!(Level::from_str("invalid").is_err());
        assert!(Level::from_str("").is_err());
    }
}
